<?php
/**
 * SocialEngine
 *
 * @category   Application_Core
 * @package    Authorization
 * @copyright  Copyright 2006-2010 Webligo Developments
 * @license    http://www.socialengine.net/license/
 * @version    $Id: Permissions.php 7566 2010-10-06 00:18:16Z john $
 * @author     John
 */

/**
 * @category   Application_Core
 * @package    Authorization
 * @copyright  Copyright 2006-2010 Webligo Developments
 * @license    http://www.socialengine.net/license/
 */
class Authorization_Model_DbTable_Permissions extends Engine_Db_Table implements Authorization_Model_AdapterInterface {
	public function getAdapterName() {
		return 'levels';
	}
	
	public function getAdapterPriority() {
		return 150;
	}
	
	public function isAllowed($resource, $role, $action) {
		// This is intended for lists
		if (is_object ( $role ) && ! empty ( $role->ignorePermCheck )) {
			return Authorization_Api_Core::LEVEL_IGNORE;
		}
		
		// Trigger warning for string roles?
		//if( is_string($role) ) {
		//  trigger_error('String role permissions checking should query Authorzation_Model_DbTable_Allow directly.', E_USER_WARNING);
		//  Zend_Registry::get('Zend_Log')->log('String role permissions checking should query Authorzation_Model_DbTable_Allow directly.', Zend_Log::WARN);
		//}
		

		// Get
		$row = $this->_getAllowed ( $resource, $role, $action );
		
		// Row was not found
		if (! is_object ( $row )) {
			return Authorization_Api_Core::LEVEL_DISALLOW;
		}
		
		// Params not correct
		if (null === Authorization_Api_Core::getConstantKey ( $row->value )) {
			return Authorization_Api_Core::LEVEL_DISALLOW;
		}
		
		return $row->value;
	}
	
	public function getAllowed($resource, $role, $action) {
		$data = $this->_getAllowed ( $resource, $role, $action );
		$isMulti = (null === $action || is_array ( $action ));
		
		// No data
		if (null === $data || count ( $data ) === 0) {
			return ($isMulti ? array () : null);
		}
		
		// Improper data returned
		if (($isMulti && ! ($data instanceof Zend_Db_Table_Rowset_Abstract)) || (! $isMulti && ! ($data instanceof Zend_Db_Table_Row_Abstract))) {
			throw new Authorization_Model_Exception ( 'improper data retrieved from _getAllowed()' );
		}
		
		// return
		if (! $isMulti) {
			// Row is a non-boolean
			if ($data->value == Authorization_Api_Core::LEVEL_NONBOOLEAN) {
				return $data->params;
			} else if ($data->value == Authorization_Api_Core::LEVEL_SERIALIZED) {
				return Zend_Json::decode ( $data->params );
			}
			
			// Row is a allow/disallow
			return $data->value;
		} 

		else {
			$rawData = array ();
			foreach ( $data as $row ) {
				// Row is a non-boolean
				if ($row->value == Authorization_Api_Core::LEVEL_NONBOOLEAN) {
					$rawData [$row->name] = $row->params;
				} else if ($row->value == Authorization_Api_Core::LEVEL_SERIALIZED) {
					$rawData [$row->name] = Zend_Json::decode ( $row->params );
				} // Row is a allow/disallow
				else {
					$rawData [$row->name] = $row->value;
				}
			}
			
			return $rawData;
		}
	}
	
	public function setAllowed($resource, $role, $action, $value = null) {
		// Can set multiple actions
		if (is_array ( $action )) {
			foreach ( $action as $key => $value ) {
				$this->setAllowed ( $resource, $role, $key, $value );
			}
			
			return $this;
		}
		
		// Check type
		$type = $this->_getResourceType ( $resource );
		if (! $type) {
			throw new Authorization_Model_Exception ( "Resource must be an instance of Core_Model_Item_Abstact or a resource type string" );
		}
		
		// Role must be a level id or a user object with a level id
		if ($role instanceof Core_Model_Item_Abstract) {
			$level_id = (isset ( $role->level_id ) ? $role->level_id : 0);
		} 

		else if (is_numeric ( $role )) {
			$level_id = $role;
		}
		
		if (! $level_id) {
			throw new Authorization_Model_Exception ( "Role must be an instance of Core_Model_Item_Abstact with a level_id or a level id" );
		}
		
		// If value not specified, set to disallow
		if ($value === null) {
			$value = Authorization_Api_Core::LEVEL_DISALLOW;
		}
		
		// Set info
		// Check for existing row
		$row = $this->fetchRow ( array ('level_id = ?' => $level_id, 'type = ?' => $type, 'name = ?' => $action ) );
		
		if (is_null ( $row )) {
			$row = $this->createRow ();
			$row->level_id = $level_id;
			$row->type = $type;
			$row->name = $action;
		}
		
		if (null !== Authorization_Api_Core::getConstantKey ( $value )) {
			$row->value = $value;
			$row->params = null;
		} else {
			if (is_scalar ( $value )) {
				$row->value = Authorization_Api_Core::LEVEL_NONBOOLEAN;
				$row->params = $value;
			} else if (is_array ( $value )) {
				$row->value = Authorization_Api_Core::LEVEL_SERIALIZED;
				$row->params = Zend_Json::encode ( $value );
			} else {
				throw new Authorization_Model_Exception ( 'non-scalar, non-array value passed to setAllowed()' );
			}
		}
		
		$row->save ();
		
		return $this;
	}
	
	// Utility
	

	protected function _getAllowed($resource, $role, $action) {
		// Must get a user object and a resource type
		$type = $this->_getResourceType ( $resource );
		if (null === $type) {
			return null;
		}
		
		// Role must be a level id or a user object with a level id
		if ($role instanceof Core_Model_Item_Abstract) {
			$level_id = (isset ( $role->level_id ) ? $role->level_id : 0);
		} 

		else if (is_numeric ( $role )) {
			$level_id = $role;
		}
		
		if (empty ( $level_id )) {
			$level_id = Engine_Api::_ ()->getDbtable ( 'levels', 'authorization' )->getPublicLevel ()->level_id;
		}
		
		// Lookup permission
		$select = $this->select ()->where ( 'level_id = ?', $level_id )->where ( 'type = ?', $type );
		
		$return = null;
		if (null === $action) {
			// get everything?
			$return = $this->fetchAll ( $select );
		} else if (is_array ( $action )) {
			if (empty ( $action )) {
				// get everything?
				$return = $this->fetchAll ( $select );
			} else {
				$select->where ( 'name IN(?)', $action );
				$return = $this->fetchAll ( $select );
			}
		} else if (is_scalar ( $action )) {
			$select->where ( 'name = ?', $action );
			$return = $this->fetchRow ( $select );
		} else {
			throw new Authorization_Model_Exception ( 'invalid action passed to _getAllowed()' );
		}
		
		return $return;
	}
	
	protected function _getLevel($level) {
		if (is_numeric ( $level )) {
			return $level;
		} else if ($level instanceof Zend_Db_Table_Row_Abstract && isset ( $level->level_id ) && is_numeric ( $level->level_id )) {
			return $level->level_id;
		} else {
			throw new Authorization_Model_Exception ( 'Invalid level id' );
		}
	}
	
	protected function _getResourceType($resource) {
		if (is_string ( $resource )) {
			return $resource;
		} 

		else if (is_array ( $resource ) && isset ( $resource [0] )) {
			return $resource [0];
		} 

		else if ($resource instanceof Core_Model_Item_Abstract) {
			return $resource->getType ();
		} 

		else {
			return null;
		}
	}
	
	protected function _getResourceIdentity($resource) {
		if (is_numeric ( $resource )) {
			return $resource;
		} 

		else if (is_array ( $resource ) && isset ( $resource [1] )) {
			return $resource [1];
		} 

		else if ($resource instanceof Core_Model_Item_Abstract) {
			return $resource->getIdentity ();
		} 

		else {
			return null;
		}
	}
}